package com.tannuo.dolphinnotedemo.sdk.device.wifi;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiManager;
import android.os.SystemClock;
import android.provider.Settings;
import android.util.Log;

import com.tannuo.dolphinnotedemo.sdk.device.protocol.IMessage;
import com.tannuo.dolphinnotedemo.sdk.device.protocol.IProtocol;
import com.tannuo.dolphinnotedemo.sdk.device.protocol.ProtocolBase;
import com.tannuo.dolphinnotedemo.sdk.device.protocol.ZDMessage;
import com.tannuo.dolphinnotedemo.sdk.util.Logger;
import com.tannuo.dolphinnotedemo.sdk.util.WifiUtil;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * Created by hucn on 2016/7/29.
 * Description: 管理与设备的wifi连接
 */
public class WifiService {

    private final String TAG = WifiService.class.getSimpleName();

    private Context mContext;

    private onReceiveListener mReceiveListener;
    private WifiManager mWifiManager;
    private ConnectivityManager mConnectivityManager;
    private String UDP_CLIENT_IP; // 本地IP地址
    private String UDP_DEVICE_IP; // 设备的IP地址
    private String UDP_MULTI_IP = "192.168.1.255"; // 广播的IP;


    private int UDP_CLIENT_MULTI_PORT = 1234; // 本地IP地址
    private int UDP_CLIENT_PORT = 1235; // 本地IP地址

    private int UDP_DEVICE_MULTI_PORT = 1236; // 远程端口
    private int UDP_DEVICE_PORT = 1237; // 远程端口

    private DatagramSocket mUdpSocket;
    private DatagramSocket mMultiSocket;
    private String mDeviceId;

    private IProtocol mProtocol;

    private int mWifiState = WifiDeviceBase.WIFI_STATE_NONE;

    private MultiSendThread mMultiSendThread;
    private MultiReceiveThread mMultiReceiveThread;

    private UdpSendThread mUdpSendThread;
    private UdpReceiveThread mUdpReceiveThread;

    private final int VOICE_MAX_QUEUE_SIZE = 200;

    private LinkedBlockingQueue<byte[]> mSendQueue = new LinkedBlockingQueue<>(VOICE_MAX_QUEUE_SIZE);

    public WifiService(Context context, IProtocol protocol) {
        mContext = context;
        mProtocol = protocol;
    }

    public void init() {
        initParams();
    }

    public void create() {
        if (checkWifiConnected()) {
            getWifiInfo();
            if (UDP_CLIENT_IP != null && (!"0.0.0.0".equals(UDP_CLIENT_IP))) {
                createMultiSocket();
            }
        } else {
            mWifiState = WifiDeviceBase.WIFI_ERROR_NOT_ENABLE;
            Logger.e(TAG, "Wifi is not enable, please check the wifi settings");
        }
    }

    private void initParams() {
        // WifiManager
        mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
        // ConnectivityManager主要管理和网络连接相关的操作
        mConnectivityManager = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
        // 获得手机唯一识别码
        mDeviceId = Settings.Secure.getString(mContext.getContentResolver(), Settings.Secure.ANDROID_ID);
    }

    private void createMultiSocket() {
        try {
            mMultiSocket = new DatagramSocket(new InetSocketAddress(
                    UDP_MULTI_IP, UDP_CLIENT_MULTI_PORT));
        } catch (IOException e) {
            mWifiState = WifiDeviceBase.WIFI_ERROR_INIT_FAILED;
            e.printStackTrace();
        }
    }

    private void createUdpSocket() {
        if (UDP_DEVICE_IP != null) {
            try {
                mUdpSocket = new DatagramSocket(new InetSocketAddress(
                        UDP_DEVICE_IP, UDP_DEVICE_PORT));
            } catch (SocketException e) {
                mWifiState = WifiDeviceBase.WIFI_ERROR_INIT_FAILED;
                e.printStackTrace();
            }
        } else {
            mWifiState = WifiDeviceBase.WIFI_ERROR_NOT_ENABLE;
            Logger.e(TAG, "Device's IP address is null");
        }
    }

    public void connect() {
        init();
        create();
        tryConnecting();
    }

    public void disconnect() {
        mWifiState = WifiDeviceBase.WIFI_STATE_DISCONNECTED;
        clearSocket();
        clearThread();
    }

    private void tryConnecting() {
        mWifiState = WifiDeviceBase.WIFI_STATE_CONNECTING;
        mMultiSendThread = new MultiSendThread();
        mMultiSendThread.start();
        mMultiReceiveThread = new MultiReceiveThread();
        mMultiReceiveThread.start();
    }

    /**
     * 组网发送线程
     */
    private class MultiSendThread extends Thread {

        private boolean isStoped = true;

        @Override
        public void run() {
            Log.i(TAG, "Multi socket Send Thread Start.");
            this.setName(MultiSendThread.class.getName());
            IMessage message = new ZDMessage();
            message.setFeature(ProtocolBase.STATUS_REQUEST_CONNECTING);
            ByteBuffer byteBuffer = ByteBuffer.allocate(28);
            byteBuffer.put(new byte[4]);
            byteBuffer.put(new byte[16]);
            byteBuffer.put(new byte[8]);
            byte[] multiData = byteBuffer.array();
            message.setCommondContent(multiData);
            byte[] data = mProtocol.encode(message);
            final DatagramPacket packet = new DatagramPacket(data, data.length);
            packet.setSocketAddress(new InetSocketAddress("192.168.1.255", UDP_DEVICE_MULTI_PORT));
            try {
                while (!isStoped || !Thread.interrupted()) {
                    synchronized (this) {
                        while (mWifiState == WifiDeviceBase.WIFI_STATE_CONNECTED) {
                            wait();
                        }
                    }
                    if (mMultiSocket != null && mMultiSocket.isBound()) {
                        try {
                            mMultiSocket.send(packet);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    Logger.d(TAG, "send multi message to search data");
                    SystemClock.sleep(1000);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        public void finish(boolean flag) {
            isStoped = flag;
        }
    }

    /**
     * 组网接收线程
     */
    private class MultiReceiveThread extends Thread {
        private boolean isStoped = true;

        @Override
        public void run() {
            Log.i(TAG, "Multi socket receive thread start.");
            this.setName(MultiSendThread.class.getName());
            try {
                while (!isStoped || !Thread.interrupted()) {
                    synchronized (this) {
                        while (mWifiState == WifiDeviceBase.WIFI_STATE_CONNECTED) {
                            wait();
                        }
                    }

                    if (mMultiSocket != null && mMultiSocket.isBound()) {
                        byte[] data = new byte[1024];
                        DatagramPacket packet = new DatagramPacket(data, data.length);
                        try {
                            mMultiSocket.receive(packet);
                            IMessage message = mProtocol.decode(packet.getData());
                            if (message.getFeature() == ProtocolBase.STATUS_RESPONSE_CONNECTING_SUCCESS) {
                                if (mWifiState != WifiDeviceBase.WIFI_STATE_CONNECTED) {
                                    String host = WifiUtil.convertIntIpAddress(WifiUtil.byte2Int(((InetSocketAddress) packet.
                                            getSocketAddress()).getAddress().getAddress()));
                                    mWifiState = WifiDeviceBase.WIFI_STATE_CONNECTED;
                                    if (!UDP_DEVICE_IP.equals(host)) {
                                        // // TODO: 2016/7/29 关闭当前的socket，创建一个新的socket
                                    } else {
                                        createUdpSocket();
                                        mUdpSendThread = new UdpSendThread();
                                        mUdpSendThread.start();
                                        mUdpReceiveThread = new UdpReceiveThread();
                                        mUdpReceiveThread.start();
                                    }
                                } else {
                                    Logger.e(TAG, "Connection status is connected, no need to reset");
                                }
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    Logger.d(TAG, "send multi message to search data");
                    SystemClock.sleep(1000);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        public void finish(boolean flag) {
            isStoped = flag;
        }
    }

    /**
     * 组网发送线程
     */
    private class UdpSendThread extends Thread {
        private boolean isStoped = true;

        @Override
        public void run() {
            this.setName(MultiSendThread.class.getName());
            Log.i(TAG, "Udp socket send thread start.");
            try {
                while (!isStoped || !Thread.interrupted()) {
                    synchronized (this) {
                        while (mWifiState == WifiDeviceBase.WIFI_STATE_CONNECTED) {
                            wait();
                        }
                    }
                    byte[] data = mSendQueue.take();
                    DatagramPacket packet = new DatagramPacket(data, data.length);
                    packet.setSocketAddress(new InetSocketAddress(UDP_DEVICE_IP, UDP_DEVICE_MULTI_PORT));

                    if (mMultiSocket != null && mMultiSocket.isBound()) {
                        try {
                            mMultiSocket.send(packet);
                            Logger.d(TAG, "Send udp message to device");
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    } else {
                        Logger.e(TAG, "The socket is not bounded or is null, discard the message");
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        public void finish(boolean flag) {
            isStoped = flag;
        }
    }

    /**
     * 组网接收线程
     */
    private class UdpReceiveThread extends Thread {
        private boolean isStoped = true;

        @Override
        public void run() {
            this.setName(MultiSendThread.class.getName());
            try {
                while (!isStoped || !Thread.interrupted()) {
                    synchronized (this) {
                        while (mWifiState != WifiDeviceBase.WIFI_STATE_CONNECTED) {
                            wait();
                        }
                    }

                    if (mMultiSocket != null && mMultiSocket.isBound()) {
                        byte[] data = new byte[1024 * 10];
                        DatagramPacket packet = new DatagramPacket(data, data.length);
                        try {
                            mMultiSocket.receive(packet);
                            if (mReceiveListener != null) {
                                mReceiveListener.onReceive(data);
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    Logger.d(TAG, "send multi message to search data");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        public void finish(boolean flag) {
            isStoped = flag;
        }
    }


    private void clearSocket() {
        if (mMultiSocket != null) {
            mMultiSocket.close();
            mMultiSocket = null;
        }
        if (mUdpSocket != null) {
            mUdpSocket.close();
            mUdpSocket = null;
        }
    }

    private void clearThread() {
        if (mMultiSendThread != null) {
            mMultiSendThread.finish(true);
            mMultiSendThread = null;
        }
        if (mMultiReceiveThread != null) {
            mMultiReceiveThread.finish(true);
            mMultiReceiveThread = null;
        }
        if (mUdpSendThread != null) {
            mUdpSendThread.finish(true);
            mUdpSendThread = null;
        }
        if (mUdpReceiveThread != null) {
            mUdpReceiveThread.finish(true);
            mUdpReceiveThread = null;
        }
    }

    private void getWifiInfo() {
        // 192.168.1.100/24
        //// TODO: 2016/7/29 android 6.0 是否应该加权限
        UDP_CLIENT_IP = WifiUtil.convertIntIpAddress(mWifiManager.getConnectionInfo().getIpAddress());
    }

    /**
     * 判断wifi是否连接
     */
    private boolean checkWifiConnected() {
        NetworkInfo wifiNetworkInfo = mConnectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
        return wifiNetworkInfo.isConnected();
    }

    public interface onReceiveListener {
        void onReceive(byte[] data);
    }

    public void setOnReceiveListener(onReceiveListener receiveListener) {
        mReceiveListener = receiveListener;
    }

    public void beatAlive() {

    }
}
